//
// Created by h00422988 on 2021/8/20.
//
#ifdef __ANDROID__

#define LOG_TAG "AudioTrackSink"

#include "utils/constants.h"
#include "foundation/log.h"
#include "audio_track_sink_plugin.h"
#include "plugins/ffmpeg_adapter/utils/ffmpeg_utils.h"

#define RETURN_ERROR_IF_CHECK_ERROR(typenames, value) \
if (value.Type() != typeid(typenames)) { \
    return Status::ERROR_MISMATCHED_TYPE; \
}


namespace {
using namespace OHOS::Media::Plugin;

std::shared_ptr<AudioSinkPlugin> AudioSinkPluginCreator(const std::string &name)
{
    return std::make_shared<AudioTrackSinkPlugin>(name);
}

const Status AudioTrackRegister(std::shared_ptr<Register> reg) {
    AudioSinkPluginDef definition;
    definition.name = "android_audio_track_sink";
    definition.rank = 100;
    definition.inCaps.push_back(Capability(OHOS::Media::MEDIA_MIME_AUDIO_RAW));
    definition.creator = AudioSinkPluginCreator;
    return reg->AddPlugin(definition);
}

PLUGIN_DEFINITION(AudioTrackSink, LicenseType::APACHE_V2, AudioTrackRegister, []{});
}

namespace OHOS {
namespace Media {
namespace Plugin {
AudioTrackSinkPlugin::AudioTrackSinkPlugin(std::string name) : AudioSinkPlugin(name), aliasName_(std::move(name)), audioTrack_(std::make_shared<AudioTrackProxy>())
{
}
Status AudioTrackSinkPlugin::Init()
{
    return Status::OK;
}

Status AudioTrackSinkPlugin::Deinit()
{
    return Status::OK;
}

Status AudioTrackSinkPlugin::Prepare()
{
    if (!audioTrack_->Open(sampleRate_, sampleFormat_, channels_, channelMask_, samplesPerFrame_)){
        MEDIA_LOG_E("open audio track error");
        return Status::ERROR_UNKNOWN;
    }
    return Status::OK;
}

Status AudioTrackSinkPlugin::Reset()
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::Start()
{
    audioTrack_->Play();
    return Status::OK;
}

Status AudioTrackSinkPlugin::Stop()
{
    audioTrack_->Stop();
    return Status::OK;
}

bool AudioTrackSinkPlugin::IsParameterSupported(Tag tag)
{
    return false;
}

Status AudioTrackSinkPlugin::GetParameter(Tag tag, ValueType &value)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::SetParameter(Tag tag, const ValueType &value)
{
    switch (tag) {
        case Tag::AUDIO_CHANNELS: {
            RETURN_ERROR_IF_CHECK_ERROR(uint32_t, value);
            channels_ = Plugin::AnyCast<uint32_t>(value);
            break;
        }
        case Tag::AUDIO_SAMPLE_RATE: {
            RETURN_ERROR_IF_CHECK_ERROR(uint32_t, value);
            sampleRate_ = Plugin::AnyCast<uint32_t>(value);
            break;
        }
        case Tag::AUDIO_SAMPLE_PER_FRAME: {
            RETURN_ERROR_IF_CHECK_ERROR(uint32_t, value);
            samplesPerFrame_ = Plugin::AnyCast<uint32_t>(value);
            break;
        }
        case Tag::AUDIO_CHANNEL_LAYOUT: {
            RETURN_ERROR_IF_CHECK_ERROR(AudioChannelLayout, value);
            auto channelLayout = Plugin::AnyCast<AudioChannelLayout>(value);
            channelMask_ = ConvertChannelLayoutToFFmpeg(channelLayout);
            break;
        }
        case Tag::AUDIO_SAMPLE_FORMAT: {
            RETURN_ERROR_IF_CHECK_ERROR(AudioSampleFormat, value);
            sampleFormat_ = Plugin::AnyCast<AudioSampleFormat>(value);
            break;
        }
        default:
            MEDIA_LOG_I("receive one parameter with unconcern key");
            break;
    }
    return Status::OK;
}

Status AudioTrackSinkPlugin::GetState(State &state)
{
    return Status::ERROR_UNIMPLEMENTED;
}

std::shared_ptr<Allocator> AudioTrackSinkPlugin::GetAllocator()
{
    return std::shared_ptr<Allocator>();
}

Status AudioTrackSinkPlugin::SetCallback(const std::shared_ptr<Callback> &cb)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::GetMute(bool &mute)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::SetMute(bool mute)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::GetVolume(float &volume)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::SetVolume(float volume)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::GetSpeed(float &speed)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::SetSpeed(float speed)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::Pause()
{
    audioTrack_->Pause();
    return Status::OK;
}

Status AudioTrackSinkPlugin::Resume()
{
    audioTrack_->Play();
    return Status::OK;
}

Status AudioTrackSinkPlugin::GetLatency(uint64_t &ms)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::GetFrameSize(size_t &size)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::GetFrameCount(uint32_t &count)
{
    return Status::ERROR_UNIMPLEMENTED;
}

Status AudioTrackSinkPlugin::Write(const std::shared_ptr<Buffer> &input)
{
    if (input && !input->IsEmpty()) {
        if (!audioTrack_->Write(const_cast<uint8_t *>(input->GetMemory()->GetReadOnlyData()), input->GetMemory()->GetSize())) {
            MEDIA_LOG_E("audio track write error");
            return Status::ERROR_UNKNOWN;
        }
    }
    return Status::OK;
}

Status AudioTrackSinkPlugin::Flush()
{
    audioTrack_->Flush();
    return Status::OK;
}
}
}
}
#endif